package dq.study.concurrent.forkjoin;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;

/**
 * Fork/Join框架的使用：
 * 本质将一个工作分解成多份，通过多个线程执行，每个线程都有自己的任务队列，其中某些线程执行完成后，可以从其他线程的队列拿任务执行（工作窃取算法）
 *
 * fork/join的主要元素
 *<p>ForkJoinTask:代表任务，提供fork和join的机制，能够分出子任务和合并任务结果
 * <b>两个主要实现子类RecursiveTask（返回结果）和RecursiveAction（不返回结果）</b>
 * <p/>
 *
 * <p>ForkJoinPool:ForkJoinTask需要通过ForkJoinPool来执行，任务分割出的子任务会添加到<b>当前工作线程所维护的双端队列中</b>，进入队列的头部。
 * 当一个工作线程的队列里暂时没有任务时，它会随机从其他工作线程的队列的尾部获取一个任务。
 * </p>
 *
 * @author dongqun
 * @version 1.0.0
 * @since 2020/12/21 15:54:00
 */
public class ForkJoinCalculateTask extends RecursiveTask<Integer> {

    private final static int threshold = 2;
    private int start;
    private int end;

    public ForkJoinCalculateTask(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        int sum = 0;
        if (end - start <= threshold) {
            for (int i = start; i <= end; i++) {
                sum += i;
                System.out.println("--"+i+"--");
            }
        } else {
            int middle = (start + end) / 2;
            ForkJoinCalculateTask leftTask = new ForkJoinCalculateTask(start, middle);
            ForkJoinCalculateTask rightTask = new ForkJoinCalculateTask(middle + 1, end);
            // 执行子任务
            leftTask.fork();
            rightTask.fork();
            // 等待子任务执行完，获得其结果
            int left = leftTask.join();
            int right = rightTask.join();
            System.out.println("---------------------------");
            sum = left + right;
        }
        return sum;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ForkJoinPool joinPool = new ForkJoinPool();
        ForkJoinCalculateTask task = new ForkJoinCalculateTask(0, 10);
        Future<Integer> future = joinPool.submit(task);
        if (task.isCompletedAbnormally()){
            System.out.println(task.getException());
        }
        System.out.println(future.get());
    }
}
